home *** CD-ROM | disk | FTP | other *** search
Oberon Text | 1994-07-11 | 15.7 KB | 452 lines | [.Ob./.Ob4] |
- Syntax10.Scn.Fnt
- StampElems
- Alloc
- 11 Jul 94
- Syntax10b.Scn.Fnt
- FoldElems
- MODULE Profiler; (* profiler for block frequencies / HM
- IMPORT Display, Oberon, Input, Fonts, Texts, TextFrames, Files, Viewers, MenuViewers;
- CONST
- nKeys = 13; (*number of keywords*)
- maxCounters = 1000; (*max. number of block counters*)
- Name = ARRAY 32 OF CHAR;
- Counter* = RECORD
- n*, beg, end: LONGINT;
- END;
- Module* = POINTER TO ModDesc;
- ModDesc* = RECORD
- name: Name;
- c*: POINTER TO ARRAY OF Counter;
- next: Module
- END;
- SourceFrame = POINTER TO SourceFrameDesc;
- CounterFrame = POINTER TO CounterFrameDesc;
- SourceFrameDesc = RECORD (TextFrames.FrameDesc)
- ctrFrame: CounterFrame
- END;
- CounterFrameDesc = RECORD (TextFrames.FrameDesc)
- mod: Module;
- srcFrame: SourceFrame;
- counters: INTEGER;
- c: POINTER TO ARRAY OF Counter
- END;
- c*: ARRAY maxCounters OF Counter;
- nextCT: INTEGER; (*index of next free counter*)
- firstMod: Module;
- stack: ARRAY 64 OF LONGINT;
- sp: INTEGER;
- key: ARRAY nKeys, 16 OF CHAR;
- inPos, outPos, begPos: LONGINT;
- level, returnLevel, procCtr: INTEGER;
- inCode, caseBegin, inWith, hasImports: BOOLEAN;
- compiler: ARRAY 32 OF CHAR;
- neutralize: Oberon.ControlMsg;
- R: Texts.Reader;
- w: Texts.Writer;
- src: Texts.Text;
- ch: CHAR;
- (*--------------------------- basic routines -----------------------------------*)
- PROCEDURE NewMod (name: Name);
- VAR m, last: Module; i: INTEGER;
- BEGIN
- m := firstMod;
- WHILE (m # NIL) & (name # m.name) DO last := m; m := m.next END;
- IF m # NIL THEN
- IF m = firstMod THEN firstMod := m.next ELSE last.next := m.next END
- END;
- NEW(m); m.next := firstMod; firstMod := m;
- m.name := name;
- IF nextCT > 0 THEN
- NEW(m.c, nextCT);
- FOR i := 0 TO nextCT-1 DO
- m.c[i].beg := c[i].beg; m.c[i].end := c[i].end; m.c[i].n := 0
- END
- END NewMod;
- PROCEDURE NewRange (pos: LONGINT; VAR n: INTEGER);
- BEGIN
- n := nextCT; INC(nextCT); c[n].beg := pos; stack[sp] := n; INC(sp)
- END NewRange;
- PROCEDURE EndRange (pos: LONGINT);
- VAR n: LONGINT;
- BEGIN
- DEC(sp); n := stack[sp]; IF pos = c[n].beg THEN INC(pos) END; c[n].end := pos; c[n].n := 0
- END EndRange;
- (*---------------------------- instrumentation ---------------------------------*)
- PROCEDURE PutS (s: ARRAY OF CHAR);
- BEGIN Texts.WriteString(w, s)
- END PutS;
- PROCEDURE PutI (x: LONGINT);
- BEGIN Texts.WriteInt(w, x, 0)
- END PutI;
- PROCEDURE Get;
- BEGIN Texts.Read(R, ch); INC(inPos); INC(outPos)
- END Get;
- PROCEDURE Insert (at: LONGINT);
- BEGIN
- outPos := outPos + w.buf.len; Texts.Insert(src, at, w.buf);
- Texts.OpenReader(R, src, outPos) (*ch still the same*)
- END Insert;
- PROCEDURE StartRange (VAR c: INTEGER);
- BEGIN
- NewRange(inPos, c);
- PutS("INC(CM.c["); PutI(c); PutS("].n);"); Insert(outPos)
- END StartRange;
- PROCEDURE GetName (VAR name: Name);
- VAR i: INTEGER;
- BEGIN
- WHILE ch = " " DO Get END;
- IF (CAP(ch) >= "A") & (CAP(ch) <= "Z") THEN
- i := 0;
- WHILE (ch >= "0") & (ch <= "9") OR (CAP(ch) >= "A") & (CAP(ch) <= "Z") DO
- name[i] := ch; INC(i); Get
- END;
- name[i] := 0X
- ELSE name := ""
- END GetName;
- PROCEDURE ReadName;
- VAR len, ct: INTEGER; iPos, oPos: LONGINT; id: Name;
- PROCEDURE Key(id: ARRAY OF CHAR): INTEGER;
- VAR i, j, m: INTEGER;
- BEGIN
- i := 0; j := nKeys - 1;
- REPEAT
- m := (i+j) DIV 2;
- IF id < key[m] THEN j := m - 1 ELSE i := m + 1 END
- UNTIL i > j;
- IF (j < 0) OR (key[j] # id) THEN RETURN -1 ELSE RETURN j END
- END Key;
- PROCEDURE ImportProfiler;
- VAR s: Texts.Scanner;
- BEGIN
- Texts.OpenScanner(s, src, 0);
- REPEAT Texts.Scan(s) UNTIL s.s = "MODULE";
- REPEAT Texts.Scan(s) UNTIL (s.class = Texts.Char) & (s.c = ";");
- PutS("IMPORT Profiler; VAR CM: Profiler.Module;");
- Insert(Texts.Pos(s)-1);
- hasImports := TRUE
- END ImportProfiler;
- BEGIN
- len := 0;
- REPEAT
- id[len] := ch; INC(len); Get
- UNTIL ~((ch >= "0") & (ch <= "9") OR (CAP(ch) >= "A") & (CAP(ch) <= "Z"));
- id[len] := 0X;
- CASE Key(id) OF
- -1: (*no keyword*)
- | 0: (*BEGIN*)
- inCode := TRUE; begPos := outPos; StartRange(procCtr);
- IF ~hasImports THEN ImportProfiler END
- | 1, 6, 8, 10: (*DO, LOOP, REPEAT, THEN*)
- StartRange(ct); INC(level)
- | 2: (*ELSE*)
- EndRange(inPos - 5); StartRange(ct)
- | 3, 11: (*ELSIF, UNTIL*)
- EndRange(inPos - 6); DEC(level)
- | 4: (*END*)
- IF level > 0 THEN (*end of statement*)
- EndRange(inPos - 4);
- IF level <= returnLevel THEN EndRange(inPos); PutS("; "); StartRange(ct) END;
- DEC(level); IF level = 0 THEN returnLevel := 0 END
- ELSE
- iPos := inPos - 4; oPos := outPos - 4; GetName(id);
- IF id # "" THEN (*end of procedure or module*)
- IF procCtr < 0 THEN (*missing BEGIN*)
- NewRange(iPos, procCtr); begPos := oPos + 6;
- PutS("BEGIN INC(CM.c["); PutI(procCtr); PutS("].n)")
- END;
- EndRange(iPos);
- Insert(oPos);
- WHILE ch = " " DO Get END;
- IF ch = "." THEN
- NewMod(id); PutS("Profiler.GetModule('"); PutS(id); PutS("', CM);"); Insert(begPos)
- END;
- inCode := FALSE; returnLevel := 0; procCtr := -1
- END
- END
- | 5: (*IMPORT*)
- WHILE ch # ";" DO Get END;
- PutS(", Profiler"); Insert(outPos-1);
- PutS("VAR CM: Profiler.Module;"); Insert(outPos);
- hasImports := TRUE
- | 7: (*OF*)
- caseBegin := inCode
- | 9: (*RETURN*)
- returnLevel := level
- | 12: (*WITH*)
- inWith := TRUE
- END ReadName;
- PROCEDURE SkipComment;
- BEGIN Get;
- LOOP
- IF ch = "*" THEN Get; IF ch = ")" THEN Get; EXIT END
- ELSIF ch = "(" THEN Get; IF ch = "*" THEN SkipComment END
- ELSE Get
- END
- END SkipComment;
- PROCEDURE Process (name: ARRAY OF CHAR);
- VAR ch0: CHAR; ct, res: INTEGER; par: Oberon.ParList;
- BEGIN
- PutS(name); PutS(" profiling "); Texts.Append(Oberon.Log, w.buf);
- nextCT := 0; procCtr := -1; sp := 0;
- level := 0; returnLevel := 0; inCode := FALSE; caseBegin := FALSE; inWith := FALSE; hasImports := FALSE;
- Texts.OpenReader(R, src, 0); inPos := 0; outPos := 0; Get;
- WHILE ch # 0X DO
- CASE ch OF
- | "A".."Z", "a".."z": ReadName
- | '"', "'": ch0 := ch; REPEAT Get UNTIL ch = ch0; Get
- | "(": Get; IF ch = "*" THEN SkipComment END
- | "|": IF inCode & ~caseBegin THEN EndRange(inPos - 1); DEC(level) END;
- Get
- | ":": Get;
- IF inCode & (ch # "=") THEN
- IF inWith THEN inWith := FALSE
- ELSE caseBegin := FALSE; DEC(inPos); DEC(outPos); StartRange(ct); INC(level)
- END
- END
- | 0X:
- ELSE Get
- END
- END;
- PutI(nextCT); PutS(" counters "); Texts.WriteLn(w);
- Texts.Append(Oberon.Log, w.buf);
- Texts.Close(src, "Pro.Tmp");
- NEW(par);
- par.text := TextFrames.Text(""); par.pos := 0;
- PutS("Pro.Tmp"); Texts.Append(par.text, w.buf);
- par.vwr := Oberon.Par.vwr; par.frame := Oberon.Par.frame;
- Oberon.Call(compiler, par, FALSE, res)
- END Process;
- (*--------------------------------------------------------------------------------*)
- PROCEDURE ScanName (VAR s: Texts.Scanner);
- VAR t: Texts.Text; beg, end, time: LONGINT; v: Viewers.Viewer;
- BEGIN
- Texts.OpenScanner (s, Oberon.Par.text, Oberon.Par.pos); Texts.Scan (s);
- IF s.class = Texts.Char THEN
- IF s.c = "^" THEN
- Oberon.GetSelection(t, beg, end, time);
- IF time >= 0 THEN Texts.OpenScanner(s, t, beg); Texts.Scan(s) END
- ELSIF s.c = "*" THEN
- v := Oberon.MarkedViewer();
- Texts.OpenScanner(s, v.dsc(TextFrames.Frame).text, 0); Texts.Scan(s)
- END
- END;
- END ScanName;
- PROCEDURE Strip (VAR s: ARRAY OF CHAR);
- VAR i, j: INTEGER;
- BEGIN
- i := 0; j := -1;
- WHILE s[i] # 0X DO
- IF s[i] = "." THEN j := i END;
- INC(i)
- END;
- IF j >= 0 THEN s[j] := 0X END
- END Strip;
- PROCEDURE GetCounterData (f: CounterFrame; t: Texts.Text);
- VAR i: INTEGER;
- PROCEDURE Sort(VAR a: ARRAY OF Counter; l, r: INTEGER);
- VAR i, j: INTEGER; m: LONGINT; c: Counter;
- BEGIN
- i := l; j := r; m := a[(i+j) DIV 2].n;
- REPEAT
- WHILE a[i].n > m DO INC(i) END;
- WHILE a[j].n < m DO DEC(j) END;
- IF i <= j THEN
- c := a[i]; a[i] := a[j]; a[j] := c; INC(i); DEC(j)
- END
- UNTIL i > j;
- IF l < j THEN Sort(a, l, j) END;
- IF i < r THEN Sort(a, i, r) END
- END Sort;
- BEGIN
- Texts.Delete(t, 0, t.len);
- f.counters := SHORT(LEN(f.mod.c^)); NEW(f.c, f.counters);
- FOR i := 0 TO f.counters-1 DO f.c[i] := f.mod.c[i] END;
- Sort(f.c^, 0, f.counters-1);
- Texts.SetFont(w, Fonts.This("Syntax10x.Scn.Fnt"));
- FOR i := 0 TO f.counters-1 DO
- Texts.WriteInt(w, f.c[i].n, 7); Texts.WriteLn(w)
- END;
- Texts.SetFont(w, Fonts.Default);
- Texts.Insert(t, 0, w.buf)
- END GetCounterData;
- PROCEDURE Line (f: CounterFrame; pos: LONGINT): INTEGER;
- VAR i, x: INTEGER; lastBeg: LONGINT; c: Counter;
- BEGIN
- i := 0; x := -1; lastBeg := -1;
- WHILE i < f.counters DO (*find smallest enclosing range*)
- c := f.c[i];
- IF (c.beg <= pos) & (c.end >= pos) & (c.beg > lastBeg) THEN x := i; lastBeg := c.beg END;
- INC(i)
- END;
- RETURN x
- END Line;
- (*--------------------------------------------------------------------------------*)
- PROCEDURE SrcHandler* (f: Display.Frame; VAR m: Display.FrameMsg);
- VAR sf: SourceFrame; cf: CounterFrame; pos, org: LONGINT; line, oldLine: INTEGER;
- BEGIN
- sf := f(SourceFrame); cf := sf.ctrFrame;
- WITH m: Oberon.InputMsg DO
- IF (m.id = Oberon.track) & (m.keys # {}) & (m.X > sf.X + TextFrames.barW) THEN
- oldLine := -1;
- REPEAT
- pos := TextFrames.Pos(sf, m.X, m.Y);
- line := Line(cf, pos);
- IF (line >= 0) & (line # oldLine) THEN
- sf.handle(sf, neutralize);
- TextFrames.SetSelection(sf, cf.c[line].beg, cf.c[line].end);
- pos := 8*line; org := pos - 20; IF org < 0 THEN org := 0 END;
- cf.handle(cf, neutralize);
- TextFrames.Show(cf, org);
- TextFrames.SetSelection(cf, pos, pos + 7);
- oldLine := line
- END;
- Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, m.X, m.Y);
- Input.Mouse(m.keys, m.X, m.Y)
- UNTIL m.keys = {}
- ELSE TextFrames.Handle(f, m)
- END
- ELSE TextFrames.Handle(f, m)
- END SrcHandler;
- PROCEDURE CtrHandler* (f: Display.Frame; VAR m: Display.FrameMsg);
- VAR cf: CounterFrame; pos, oldPos, org, i: LONGINT;
- BEGIN
- cf := f(CounterFrame);
- WITH m: Oberon.InputMsg DO
- IF (m.id = Oberon.track) & (m.keys # {}) & (m.X > cf.X + TextFrames.barW) THEN
- oldPos := -1;
- REPEAT
- pos := TextFrames.Pos(cf, cf.X, m.Y);
- IF pos # oldPos THEN
- TextFrames.SetSelection(cf, pos, pos + 7); oldPos := pos
- END;
- Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, m.X, m.Y);
- Input.Mouse(m.keys, m.X, m.Y)
- UNTIL m.keys = {};
- i := pos DIV 8;
- org := cf.c[i].beg - 200; IF org < 0 THEN org := 0 END;
- cf.srcFrame.handle(cf.srcFrame, neutralize);
- TextFrames.Show(cf.srcFrame, org);
- TextFrames.SetSelection(cf.srcFrame, cf.c[i].beg, cf.c[i].end)
- ELSE TextFrames.Handle(f, m)
- END
- ELSE TextFrames.Handle(f, m)
- END CtrHandler;
- PROCEDURE GetModule* (name: ARRAY OF CHAR; VAR m: Module);
- BEGIN
- m := firstMod;
- WHILE (m # NIL) & (m.name # name) DO m := m.next END;
- END GetModule;
- PROCEDURE Compile*;
- VAR f: TextFrames.Frame; s, s0: Texts.Scanner; v: Viewers.Viewer; t: Texts.Text; beg, end, time: LONGINT;
- buf: Texts.Buffer;
- BEGIN
- f := Oberon.Par.frame(TextFrames.Frame);
- Texts.OpenScanner(s, f.text, Oberon.Par.pos);
- LOOP
- Texts.Scan(s); time := -1;
- IF (s.class = Texts.Char) & (s.c = "^") THEN
- Oberon.GetSelection(t, beg, end, time);
- IF time >= 0 THEN Texts.OpenScanner(s, t, beg); Texts.Scan(s) END
- END;
- IF s.class = Texts.Name THEN
- src := TextFrames.Text(s.s);
- Process(s.s);
- IF time >= 0 THEN EXIT END
- ELSIF (s.class = Texts.Char) & (s.c = "*") THEN
- v := Oberon.MarkedViewer();
- IF (v.dsc # NIL) & (v.dsc.next IS TextFrames.Frame) THEN
- t := v.dsc.next(TextFrames.Frame).text;
- NEW(buf); Texts.OpenBuf(buf); Texts.Save(t, 0, t.len, buf);
- src := TextFrames.Text(""); Texts.Append(src, buf);
- Texts.OpenScanner(s0, v.dsc(TextFrames.Frame).text, 0); Texts.Scan(s0);
- Process(s0.s)
- END;
- EXIT
- ELSE EXIT
- END
- END Compile;
- PROCEDURE UseCompiler*;
- VAR s: Texts.Scanner;
- BEGIN
- Texts.OpenScanner(s, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(s);
- IF s.class = Texts.Name THEN COPY(s.s, compiler) END
- END UseCompiler;
- PROCEDURE Show*;
- VAR s: Texts.Scanner; t: Texts.Text; m: Module; fn: Name; x, y: INTEGER;
- mf: TextFrames.Frame; sf: SourceFrame; cf: CounterFrame; v: Viewers.Viewer;
- PROCEDURE Append (VAR s: ARRAY OF CHAR; ext: ARRAY OF CHAR);
- VAR i, j: INTEGER;
- BEGIN
- i := 0; WHILE s[i] # 0X DO INC(i) END;
- j := 0; WHILE ext[j] # 0X DO s[i] := ext[j]; INC(i); INC(j) END;
- s[i] := 0X
- END Append;
- BEGIN
- ScanName(s);
- IF s.class = Texts.Name THEN
- Strip(s.s);
- m := firstMod; WHILE (m # NIL) & (m.name # s.s) DO m := m.next END;
- IF m = NIL THEN
- Texts.WriteString(w, s.s); Texts.WriteString(w, " not found"); Texts.WriteLn(w); Texts.Append(Oberon.Log, w.buf)
- ELSE
- COPY(s.s, fn); Append(fn, ".Mod");
- mf := TextFrames.NewMenu(fn, "System.Close System.Copy System.Grow Edit.Search");
- NEW(sf);
- TextFrames.Open(sf, TextFrames.Text(fn), 0); sf.handle := SrcHandler;
- Oberon.AllocateUserViewer(0, x, y);
- v := MenuViewers.New(mf, sf, TextFrames.menuH, x, y);
- COPY(s.s, fn); Append(fn, " counters");
- mf := TextFrames.NewMenu(fn, "System.Close System.Copy System.Grow Profiler.Update");
- t := TextFrames.Text("");
- NEW(cf); cf.mod := m; cf.srcFrame := sf; sf.ctrFrame := cf;
- GetCounterData(cf, t);
- TextFrames.Open(cf, t, 0); cf.handle := CtrHandler;
- Oberon.AllocateSystemViewer(0, x, y);
- v := MenuViewers.New(mf, cf, TextFrames.menuH, x, y)
- END
- END Show;
- PROCEDURE Reset*;
- VAR s: Texts.Scanner; m: Module; i: LONGINT;
- BEGIN
- ScanName(s);
- IF s.class = Texts.Name THEN
- Strip(s.s);
- m := firstMod; WHILE (m # NIL) & (m.name # s.s) DO m := m.next END;
- IF m = NIL THEN
- Texts.WriteString(w, s.s); Texts.WriteString(w, " not found"); Texts.WriteLn(w); Texts.Append(Oberon.Log, w.buf)
- ELSE
- FOR i := 0 TO LEN(m.c^)-1 DO m.c[i].n := 0 END
- END
- END;
- END Reset;
- (*PROCEDURE Print*;
- VAR m: Module; i: INTEGER;
- BEGIN
- m := firstMod;
- WHILE m # NIL DO
- IO.Str(m.name); IO.NL;
- FOR i := 0 TO LEN(m.c^) - 1 DO
- IO.Str(" "); IO.Int1(m.c[i].beg, 5); IO.Str(" -"); IO.Int1(m.c[i].end, 5); IO.Int1(m.c[i].n, 7); IO.NL
- END;
- m := m.next
- END Print;
- BEGIN
- key[0] := "BEGIN";
- key[1] := "DO";
- key[2] := "ELSE";
- key[3] := "ELSIF";
- key[4] := "END";
- key[5] := "IMPORT";
- key[6] := "LOOP";
- key[7] := "OF";
- key[8] := "REPEAT";
- key[9] := "RETURN";
- key[10] := "THEN";
- key[11] := "UNTIL";
- key[12] := "WITH";
- Texts.OpenWriter(w);
- compiler := "Compiler.Compile";
- firstMod := NIL;
- neutralize.id := Oberon.neutralize
- END Profiler.
-